/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * Calc.java
 *
 * Created on 5 avr. 2011, 23:04:02
 */
package examples;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.KeyStroke;
import javax.swing.text.AbstractDocument;

/**
 *
 * @author nicolas
 */
public class Calc extends javax.swing.JFrame
{

  /**
   * Mapping des touches
   */
  private Map<String, Integer> mapping;
  /**
   * Robot pour insérer des caractères <- CE ...
   */
  private Robot robot;
  /**
   * Lien vers le presse papier pour les coller
   */
  private Clipboard cb;
  /**
   * Document filter personnalisé
   */
  private CalcFilter calcFilter = new CalcFilter();
  /**
   * Premier opérande de calcul
   */
  private Double firstOperande = null;
  /**
   * Opérateur de calcul
   */
  private String operator = null;
  /**
   * Flag qui indique si le dernier caratère tapé est un opérateur. Sert à vider le champ de saisi à la frappe suivante.
   */
  private boolean lastTypedIsOperator = false;
  /**
   * Logger
   */
  private static final Logger logger = Logger.getLogger(Calc.class.getName());

  /** 
   * Creates new form Calc
   */
  public Calc() throws AWTException
  {
    initComponents();
    initMapping();
    initRobot();
    cb = Toolkit.getDefaultToolkit().getSystemClipboard();
  }

  /** This method is called from within the constructor to
   * initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is
   * always regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {
    java.awt.GridBagConstraints gridBagConstraints;

    btPad1 = new javax.swing.JButton();
    btPad2 = new javax.swing.JButton();
    btPad3 = new javax.swing.JButton();
    btPad4 = new javax.swing.JButton();
    btPad5 = new javax.swing.JButton();
    btPad6 = new javax.swing.JButton();
    btPad7 = new javax.swing.JButton();
    btPad8 = new javax.swing.JButton();
    btPad9 = new javax.swing.JButton();
    btPad0 = new javax.swing.JButton();
    btPad00 = new javax.swing.JButton();
    btPadPoint = new javax.swing.JButton();
    btPadDiv = new javax.swing.JButton();
    btPadMul = new javax.swing.JButton();
    btPadMin = new javax.swing.JButton();
    btPadAdd = new javax.swing.JButton();
    btPadDel = new javax.swing.JButton();
    jButton1 = new javax.swing.JButton();
    jButton2 = new javax.swing.JButton();
    jTextField1 = new javax.swing.JTextField();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setMinimumSize(new java.awt.Dimension(80, 60));
    getContentPane().setLayout(new java.awt.GridBagLayout());

    btPad1.setText("1");
    btPad1.setFocusPainted(false);
    btPad1.setFocusable(false);
    btPad1.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 1;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad1, gridBagConstraints);

    btPad2.setText("2");
    btPad2.setFocusable(false);
    btPad2.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 1;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad2, gridBagConstraints);

    btPad3.setText("3");
    btPad3.setFocusable(false);
    btPad3.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 1;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad3, gridBagConstraints);

    btPad4.setText("4");
    btPad4.setFocusable(false);
    btPad4.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad4, gridBagConstraints);

    btPad5.setText("5");
    btPad5.setFocusable(false);
    btPad5.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad5, gridBagConstraints);

    btPad6.setText("6");
    btPad6.setFocusable(false);
    btPad6.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad6, gridBagConstraints);

    btPad7.setText("7");
    btPad7.setFocusable(false);
    btPad7.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 3;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad7, gridBagConstraints);

    btPad8.setText("8");
    btPad8.setFocusable(false);
    btPad8.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 3;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad8, gridBagConstraints);

    btPad9.setText("9");
    btPad9.setFocusable(false);
    btPad9.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 3;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad9, gridBagConstraints);

    btPad0.setText("0");
    btPad0.setFocusable(false);
    btPad0.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 4;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad0, gridBagConstraints);

    btPad00.setText("00");
    btPad00.setFocusable(false);
    btPad00.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 1;
    gridBagConstraints.gridy = 4;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPad00, gridBagConstraints);

    btPadPoint.setText(".");
    btPadPoint.setFocusable(false);
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 2;
    gridBagConstraints.gridy = 4;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPadPoint, gridBagConstraints);

    btPadDiv.setText("/");
    btPadDiv.setFocusable(false);
    btPadDiv.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 1;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPadDiv, gridBagConstraints);

    btPadMul.setText("*");
    btPadMul.setFocusable(false);
    btPadMul.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPadMul, gridBagConstraints);

    btPadMin.setText("-");
    btPadMin.setFocusable(false);
    btPadMin.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 3;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPadMin, gridBagConstraints);

    btPadAdd.setText("+");
    btPadAdd.setFocusable(false);
    btPadAdd.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        btHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 3;
    gridBagConstraints.gridy = 4;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPadAdd, gridBagConstraints);

    btPadDel.setText("<-");
    btPadDel.setFocusable(false);
    btPadDel.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        delHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 1;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(btPadDel, gridBagConstraints);

    jButton1.setText("CE");
    jButton1.setFocusable(false);
    jButton1.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        clearHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(jButton1, gridBagConstraints);

    jButton2.setText("=");
    jButton2.setFocusable(false);
    jButton2.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseReleased(java.awt.event.MouseEvent evt) {
        equalsHandler(evt);
      }
    });
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridy = 3;
    gridBagConstraints.gridheight = 2;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    getContentPane().add(jButton2, gridBagConstraints);
    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridy = 0;
    gridBagConstraints.gridwidth = 5;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
    getContentPane().add(jTextField1, gridBagConstraints);
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed +"), "operatorHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke('+'), "operatorHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed *"), "operatorHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed /"), "operatorHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed -"), "operatorHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 1"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 2"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 3"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 4"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 5"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 6"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 7"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 8"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 9"), "numberHandler");
    jTextField1.getInputMap().put(KeyStroke.getKeyStroke("typed 0"), "numberHandler");
    jTextField1.getActionMap().put("operatorHandler", operatorAction);
    jTextField1.getActionMap().put("numberHandler", numberAction);
    AbstractDocument doc = (AbstractDocument) jTextField1.getDocument();
    doc.setDocumentFilter(calcFilter);
    //doc.addDocumentListener(new Kiss());

    pack();
  }// </editor-fold>//GEN-END:initComponents
  /**
   * Ecouteur des opérateurs
   */
  private AbstractAction operatorAction = new AbstractAction()
  {

    public void actionPerformed(ActionEvent e)
    {
      if (!lastTypedIsOperator)
      {
        try
        {
          firstOperande = Double.parseDouble(jTextField1.getText());
          logger.log(Level.FINEST, "operatorAction - firstOperande : {0}", new Object[]
                  {
                    firstOperande
                  });
        }
        catch (NumberFormatException nfe)
        {
        }
      }
      lastTypedIsOperator = true;
      operator = e.getActionCommand();
      System.out.println("operatorAction - operator : " + e.getActionCommand());
    }
  };
  /**
   * Réponse à la frappe directe au clavier
   */
  private AbstractAction numberAction = new AbstractAction()
  {

    public void actionPerformed(ActionEvent e)
    {
      char typed = e.getActionCommand().toCharArray()[0];
      System.out.println("frappe clavier : " + typed);

      if (Character.isDigit(typed))
      {
        if (lastTypedIsOperator)
        {
          lastTypedIsOperator = false;
          jTextField1.setText("");
        }
        paste(typed + "");
      }
    }
  };

  /**
   * Frappe au clavier tactile
   * @param evt
   */
    private void btHandler(java.awt.event.MouseEvent evt)//GEN-FIRST:event_btHandler
    {//GEN-HEADEREND:event_btHandler


      Object source = evt.getSource();
      String typed = ((JButton) source).getText();
      System.out.println("frappe tactile : " + typed);

      if (mapping.containsKey(typed))
      {
        robot.keyPress(mapping.get(typed));
        robot.keyRelease(mapping.get(typed));
      }
      else
      {
        if (lastTypedIsOperator)
        {
          lastTypedIsOperator = false;
          jTextField1.setText("");
        }
        paste(typed);
      }
    }//GEN-LAST:event_btHandler

    private void clearHandler(java.awt.event.MouseEvent evt)//GEN-FIRST:event_clearHandler
    {//GEN-HEADEREND:event_clearHandler
      System.out.println("Clear : CE");
      jTextField1.setText(null);
      operator = null;
      lastTypedIsOperator = false;
      firstOperande = null;
    }//GEN-LAST:event_clearHandler

    private void delHandler(java.awt.event.MouseEvent evt)//GEN-FIRST:event_delHandler
    {//GEN-HEADEREND:event_delHandler
      System.out.println("Del : <-");
      robot.keyPress(KeyEvent.VK_BACK_SPACE);
      robot.keyRelease(KeyEvent.VK_BACK_SPACE);
      operator = null;
      lastTypedIsOperator = false;
    }//GEN-LAST:event_delHandler

    private void equalsHandler(java.awt.event.MouseEvent evt)//GEN-FIRST:event_equalsHandler
    {//GEN-HEADEREND:event_equalsHandler
      System.out.println("Equals : =");
      if (firstOperande != null && operator != null)
      {
        Double lastOperande = null;
        try
        {
          lastOperande = Double.parseDouble(jTextField1.getText());
        }
        catch (NumberFormatException nfe)
        {
        }
        if (lastOperande != null)
        {
          Double result = null;
          if (operator.equals("+"))
          {
            result = firstOperande + lastOperande;
          }
          else if (operator.equals("-"))
          {
            result = firstOperande - lastOperande;
          }
          else if (operator.equals("*"))
          {
            result = firstOperande * lastOperande;
          }
          else if (operator.equals("/"))
          {
            if (lastOperande != 0.0)
            {
              result = firstOperande / lastOperande;
            }
          }
          if (result != null)
          {
            firstOperande = result;
            operator = null;
            jTextField1.setText(result.toString());
          }
        }
      }
    }//GEN-LAST:event_equalsHandler

  private void paste(String s)
  {
    StringSelection ss = new StringSelection(s);
    cb.setContents(ss, ss);
    jTextField1.paste();
  }

  private void initMapping()
  {
    mapping = new HashMap<String, Integer>();
    mapping.put("-", 109);
    mapping.put("+", 107);
    mapping.put("/", 111);
    mapping.put("*", 151);
  }

  private void initRobot()
  {
    try
    {
      robot = new Robot();
    }
    catch (AWTException ex)
    {
      // TODO déclarer le logger en champ de classe
      logger.log(Level.SEVERE, null, ex);
    }
  }

  /**
   * @param args the command line arguments
   */
  public static void main(String args[])
  {
    java.awt.EventQueue.invokeLater(new Runnable()
    {

      public void run()
      {
        try
        {
          new Calc().setVisible(true);
        }
        catch (AWTException ex)
        {
          Logger.getLogger(Calc.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
    });
  }
  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton btPad0;
  private javax.swing.JButton btPad00;
  private javax.swing.JButton btPad1;
  private javax.swing.JButton btPad2;
  private javax.swing.JButton btPad3;
  private javax.swing.JButton btPad4;
  private javax.swing.JButton btPad5;
  private javax.swing.JButton btPad6;
  private javax.swing.JButton btPad7;
  private javax.swing.JButton btPad8;
  private javax.swing.JButton btPad9;
  private javax.swing.JButton btPadAdd;
  private javax.swing.JButton btPadDel;
  private javax.swing.JButton btPadDiv;
  private javax.swing.JButton btPadMin;
  private javax.swing.JButton btPadMul;
  private javax.swing.JButton btPadPoint;
  private javax.swing.JButton jButton1;
  private javax.swing.JButton jButton2;
  private javax.swing.JTextField jTextField1;
  // End of variables declaration//GEN-END:variables
}
